#include "include/Session.h"
#include "include/Singleton.h"
#include "include/SessionManager.h"

Session::Session(boost::asio::io_service &io_service)
	: _socket(io_service), _io_service(io_service), _is_control(0)
{
	memset(_package, '\0', sizeof(_package));
}

Session::~Session()
{
}

tcp::socket & Session::Socket()
{
	return _socket;
}

void Session::Start()
{
	_is_control = 0;

	_logic.Init();
	
	Singleton<SessionManager>::instance().AddSession(this);
	
	_socket.async_read_some(boost::asio::buffer(_package, MAX_PACKAGE_SIZE),
		boost::bind(&Session::HandleRead, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}

void Session::StartControl()
{
	_is_control = 1;

	_logic.Init();

	_socket.async_read_some(boost::asio::buffer(_package, MAX_PACKAGE_SIZE),
		boost::bind(&Session::HandleReadControl, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}

void Session::HandleWrite(const boost::system::error_code &error)
{
	if(error)
	{
		DeleteSelf();
		return;
	}

	_socket.async_read_some(boost::asio::buffer(_package, MAX_PACKAGE_SIZE),
		boost::bind(&Session::HandleRead, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}

void Session::HandleRead(const boost::system::error_code &error, size_t bytes_transferred)
{
	if(error)
	{
		// debug
		cout << "Receive data Error" << endl;
		// debug end
		DeleteSelf();
		return;
	}

	// debug
	cout << "recv data: " << endl;
	for(int i = 0; i < bytes_transferred; i++)
	{
		cout << _package[i];
	}
	cout << endl << "recv data end" << endl;
	// debug end

	_package_len = (int)bytes_transferred;

	ProcessUpData(_package, _package_len);
}

void Session::HandleReadControl(const boost::system::error_code &error, size_t bytes_transferred)
{
	if(error)
	{
		// debug
		cout << "Receive data Error" << endl;
		// debug end
		DeleteSelf();
		return;
	}

	// debug
	cout << "recv data: " << endl;
	for(int i = 0; i < bytes_transferred; i++)
	{
		cout << _package[i];
	}
	cout << endl << "recv data end" << endl;
	// debug end

	_package_len = (int)bytes_transferred;

	ProcessUpData(_package, _package_len);
}

void Session::ProcessUpData(char *buf, int len)
{
	Common::DataType data_type;
	char *p_data;
	int num = _logic.ProcessData(thread_id, buf, len);

#ifdef _DEBUG_LEVEL_1_
	cout << "recv package num: " << num << endl;
#endif

	for(int i = 0; i < num; i++)
	{
		data_type = _logic.ProcessDownStreamPackage(i, p_data, len);

		switch(data_type)
		{
		case Common::DelayData:
		case Common::DelayBroadcastData:
		case Common::DelayMulticastData:
		case Common::DelayUpData:
		{
#ifdef _DEBUG_LEVEL_1_
	cout << "recv delay package: " << data_type << endl;
#endif
			StartDelay(_logic.delay_ms, p_data, len - _logic.drop_info_len, data_type);
		}
			break;

		case Common::EmptyData:
#ifdef _DEBUG_LEVEL_1_
	cout << "recv empty package: " << data_type << endl;
#endif
			break;

		default:
		{
#ifdef _DEBUG_LEVEL_1_
	cout << "recv default package: " << data_type << endl;
	cout << "data content: " << endl;
	for(int j = 0; j < len; j++)
	{
		cout << (char)(*(p_data + j));
	}

	cout << endl;
#endif
			boost::asio::async_write(_socket, boost::asio::buffer(p_data, len),
				boost::bind(&Session::HandleWrite, this, boost::asio::placeholders::error));
		}
			break;
		}
	}
}

void Session::StartDelay(long delay_ms, char *buf, int len, Common::DataType data_type)
{
	void *buffer = Singleton<DelayBufferPool>::instance().GetBuffer();
	if(NULL == buffer)
	{
		cerr << "get null delay buffer in " << __FUNCTION__ << endl;
		return;
	}

	memcpy(buffer, buf, len);

	boost::asio::deadline_timer *p_timer = new boost::asio::deadline_timer(_io_service);
	p_timer->expires_from_now(boost::posix_time::milliseconds(delay_ms));

	Common::PackageHead *p_head = PackageUtil::GetPackageHead(buffer);
	switch(data_type)
	{
	case Common::DelayData:
	{
		p_head->append_data = (int)Common::NormalData;

		p_timer->async_wait(boost::bind(&Session::CallbackDelaySend, this,
			boost::asio::placeholders::error, buffer, len, p_timer));
	}
		break;

	case Common::DelayBroadcastData:
	{
		p_head->append_data = (int)Common::BroadcastData;

		p_timer->async_wait(boost::bind(&Session::CallbackDelaySend, this,
			boost::asio::placeholders::error, buffer, len, p_timer));
	}
		break;

	case Common::DelayMulticastData:
	{
		p_head->append_data = (int)Common::MulticastData;

		p_timer->async_wait(boost::bind(&Session::CallbackDelaySend, this,
			boost::asio::placeholders::error, buffer, len, p_timer));
	}
		break;

	case Common::DelayUpData:
	{
		p_head->append_data = (int)Common::NormalData;
		
		p_timer->async_wait(boost::bind(&Session::CallbackDelayProcess, this,
			boost::asio::placeholders::error, buffer, len, p_timer));
	}
		break;

	default:
		cout << "in StartDelay, unknown data type: " << data_type << endl;
		break;
	}
}

void Session::CallbackDelaySend(const boost::system::error_code& ec, char *buf, int len,
	boost::asio::deadline_timer *p_timer)
{
	delete p_timer;
	
	boost::asio::async_write(_socket, boost::asio::buffer(buf, len),
		boost::bind(&Session::HandleWrite, this, boost::asio::placeholders::error));

	Singleton<DelayBufferPool>::instance().ReleaseBuffer(buf);
}

void Session::CallbackDelayProcess(const boost::system::error_code& ec, char *buf,
	int len, boost::asio::deadline_timer *p_timer)
{
	delete p_timer;

	memcpy(_package, buf, len);
	_package_len = len;

	Singleton<DelayBufferPool>::instance().ReleaseBuffer(buf);

	ProcessUpData(_package, _package_len);
}

void Session::DeleteSelf()
{
	Singleton<SessionManager>::instance().DelSession(this);
	delete this;
}

